#pragma once
#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
#include "TempleteFea.h"
#include "utilfun.h"
#include "utilio.h"
#include <iostream>
#include "binstore.h"
#include "map_int.h"

struct span_feature_link
{
	span_feature*	cur_span;
	span_feature_link* next;
};

struct grid_edge
{
	span_feature_link* feas_list;
	inline void push_fea(freelist<char>& pool,span_feature* spn)
	{
		span_feature_link* link = (span_feature_link*)pool.alloc(sizeof(span_feature_link));
		link->cur_span  = spn;
		link->next = feas_list;
		feas_list = link;
	}
	int	inout_idx;
	double p;
};

class invalid_grid_edge {
public:
	static grid_edge get() { 
		static invalid_grid_edge* loc_p =0;
		if(loc_p==0)
			loc_p = new invalid_grid_edge();
		return loc_p->_invalid_edge; 
	}
	invalid_grid_edge() { _invalid_edge.inout_idx=-1;_invalid_edge.feas_list = 0;}
	grid_edge _invalid_edge;
};

typedef map_base<grid_edge,invalid_grid_edge>	map_edge;

class grid_node2
{
public:
	int			  tag_id;
	map_edge	  income_edges;
	map_edge	  outcome_edges;
	double		  grid_alpha;
	double		  grid_beta;
	int					  income_spans_num;
	span_feature_link*	  income_spans;
	span_feature_link*	  outcome_spans;
	int					  outcome_spans_num;

	inline void push_income_span(freelist<char>& pool,span_feature* spn)
	{
		span_feature_link* link = (span_feature_link*)pool.alloc(sizeof(span_feature_link));
		link->cur_span  = spn;
		link->next = income_spans;
		income_spans = link;
		income_spans_num++;
	}

	inline void push_outcome_span(freelist<char>& pool,span_feature* spn)
	{
		span_feature_link* link = (span_feature_link*)pool.alloc(sizeof(span_feature_link));
		link->cur_span  = spn;
		link->next = outcome_spans;
		outcome_spans = link;
		outcome_spans_num++;
	}

	inline void init() {
		tag_id=0; income_spans = 0; outcome_spans =0; grid_alpha = -1; grid_beta = -1;outcome_spans_num=0;income_spans_num=0;
		outcome_edges._total_size = 0;income_edges._total_size = 0;
	}

	inline void collect_span_to_edge(freelist<char>& pool)
	{
		income_edges.init(pool,income_spans_num*2);
		outcome_edges.init(pool,outcome_spans_num*2);
		span_feature_link* link =income_spans;
		while(link!=0)
		{
			push_income_edge(pool,link->cur_span);
			link = link->next;
		}
		link =outcome_spans;
		while(link!=0)
		{
			push_outcome_edge(pool,link->cur_span);
			link = link->next;
		}
	}
protected:
	inline void push_income_edge(freelist<char>& pool,span_feature* spn)
	{
		int idx = income_edges.find(spn->y_pre);
		if(idx==-1)
		{
			grid_edge e;
			e.feas_list=0;
			e.inout_idx = spn->y_pre;
			e.push_fea(pool,spn);
			income_edges.insert(spn->y_pre,e);
		}
		else
		{
			grid_edge& e = income_edges.value(idx);
			assert_loc(e.inout_idx ==  spn->y_pre);
			e.push_fea(pool,spn);
		}
	}

	inline void push_outcome_edge(freelist<char>& pool,span_feature* spn)
	{
		int idx = outcome_edges.find(spn->y_cur);

		if(idx==-1)
		{
			grid_edge e;
			e.feas_list=0;
			e.inout_idx = spn->y_cur;
			e.push_fea(pool,spn);
			outcome_edges.insert(spn->y_cur,e);
		}
		else
		{
			grid_edge& e = outcome_edges.value(idx);
			assert_loc(e.inout_idx ==  spn->y_cur);
			e.push_fea(pool,spn);
		}
	}

};

class crfHolder2
{
public:
	crfHolder2() { _map_pool.set_size(1024*37*37);_link_pool.set_size(1024*37*37);}

	freelist<char>	   _map_pool;
	freelist<char>	   _link_pool;
	double	_obj;
	double*	_lambda;
	double*	_gradient;
	
	int					_tag_size;
	vector<map_int>		_tagid2gridid;

	vector<grid_node2*>	_node_grid;
	memPool<grid_node2>	_grid_memPool;

	vector<int*>		_grid_backtrack;
	memPool<int>		_backtrack_memPool;

	double*	_alpha;
	double* _beta;
	memPool<double>	    _double_pool;
	int					_tag_sentence_begin;

	void build_lattice(sentence& sen);

	void make_grid(sentence& sen);

	void calculate_alpha(sentence& sen);

	void calculate_beta(sentence& sen);

	double calculate_Z(sentence& sen);

	double calculate_cost(sentence& sen);
 
	void calculate_gradient(sentence& sen,double& z_all);

	double decode(sentence& sen,vector<int>& predict_label);

	double process_sen(sentence& sen);

	double process_decode(sentence& sen,vector<int>& predict_label);
};